#include "DefineCommon.h"
#include "ECommand.h"
#include "EController.h"
#include <ECommandManager.h>
#include <cstddef>
#include <stack>

struct ECommandManagerData
{
	std::deque<ECommandPtr> m_eventQueue;
	EList<ECommandDelegate> m_listDelegate;
    EList<EController*> m_listController;

    //for redo undo
    std::stack<ECommandPtr> m_stackOldCmd1;
    std::stack<ECommandPtr> m_stackOldCmd2;
    ECommandPtr m_cmdTimer;
};

ECommandManager* ECommandManager::m_instance = NULL;

ECommandManager::~ECommandManager()
{


}

ECommandManager::ECommandManager()
{
	m_data = new ECommandManagerData;
    m_data->m_cmdTimer = NewSmartPtr(ECommand)();
    m_data->m_cmdTimer->setName("c:timer");
    m_data->m_cmdTimer->setState(ECommand::STATE::NORMAL);
}


ECommandManager* ECommandManager::instance()
{
	if (m_instance == NULL)
	{
		m_instance = new ECommandManager();
	}

	return m_instance;
}

void ECommandManager::processECommand()
{
    //Firstly, handle cmd: m_data->m_cmdTimer
    // for(size_t i = 0; i < this->m_data->m_listDelegate.size(); i++)
    // {
        // this->m_data->m_listDelegate[i](this->m_data->m_cmdTimer);
    // }

    //Then, handle accidental commnd
    while(this->m_data->m_eventQueue.size() != 0)
    {
        for(size_t i = 0; i < this->m_data->m_listDelegate.size(); i++)
        {
            if(this->m_data->m_listDelegate[i].m_valid == true)
                this->m_data->m_listDelegate[i](this->m_data->m_eventQueue[0]);

            //handle m_data->m_cmdTimer
            // this->m_data->m_listDelegate[i](this->m_data->m_cmdTimer);
        }

        ECommandPtr topCmd = this->m_data->m_eventQueue.front();
        if(topCmd->getIfEnableUndo())
        {
            this->m_data->m_stackOldCmd1.push(
                    this->m_data->m_eventQueue.front()
                    );

            //clear m_stackOldCmd2, because a new cmd is pushed in m_stackOldCmd1.
            while(this->m_data->m_stackOldCmd2.empty() == false)
            {
                this->m_data->m_stackOldCmd2.pop();
            }
        }


        this->m_data->m_eventQueue.pop_front();
    }

}

void ECommandManager::processECommandUndoOnce()
{
    if(this->m_data->m_stackOldCmd1.size() == 0)
    {
        ELOG_INFO("no command need to undo");
        return;
    }

    ECommandPtr cmd = this->m_data->m_stackOldCmd1.top();
    cmd->setState(ECommand::STATE::UNDO);

    for(size_t i = 0; i < this->m_data->m_listDelegate.size(); i++)
    {
        if(this->m_data->m_listDelegate[i].m_valid == true)
            this->m_data->m_listDelegate[i](cmd);
    }

    this->m_data->m_stackOldCmd1.pop();
    this->m_data->m_stackOldCmd2.push(cmd);
}

void ECommandManager::processECommandRedoOnce()
{
    if(this->m_data->m_stackOldCmd2.size() == 0)
    {
        ELOG_INFO("no command need to redo");
        return;
    }
    
    ECommandPtr cmd = this->m_data->m_stackOldCmd2.top();
    cmd->setState(ECommand::STATE::REDO);

    for(size_t i = 0; i < this->m_data->m_listDelegate.size(); i++)
    {
        if(this->m_data->m_listDelegate[i].m_valid == true)
            this->m_data->m_listDelegate[i](cmd);
    }

    this->m_data->m_stackOldCmd2.pop();
    this->m_data->m_stackOldCmd1.push(cmd);
}

void ECommandManager::pushECommand( ECommandPtr event)
{
	if (event == nullptr)
	{
        ELOG_ERROR("event==null");
	}
	else
	{
		this->m_data->m_eventQueue.push_back(event);
	}
}

void ECommandManager::registDelegate(ECommandDelegate e)
{
    // this->m_data->m_listController.push_back(controllerPtr);
    this->m_data->m_listDelegate.push_back(e);
}

void ECommandManager::unregistDelegate(EController* controller)
{
    // int index = 0;
    // EList<EController*>::iterator it;
    // for(it = this->m_data->m_listController.begin(); it != this->m_data->m_listController.end(); it++)
    // {
        // if(*it == controller)
        // {
            // break;
        // }
        // index++;
    // }

    // this->m_data->m_listController.erase(it);

	// EList<ECommandDelegate>::iterator itDelegate;
    // itDelegate = this->m_data->m_listDelegate.begin()+index;
    // if(itDelegate != this->m_data->m_listDelegate.end())
    // {
        // this->m_data->m_listDelegate.erase(itDelegate);
    // }

    EList<ECommandDelegate>::iterator it;
    for(it = this->m_data->m_listDelegate.begin(); it != this->m_data->m_listDelegate.end(); it++)
    {
        if(controller == &(it->callee_))
        {
            it->m_valid = false;
            break;
        }
    }

}

